﻿using System.ComponentModel;
using System.Reflection;

namespace EvaluationSystem.Utils;

public class ReflectionUtil
{

}

public static class ReflectionExtension
{
    public static T? GetAttribute<T>(this PropertyInfo propertyInfo) where T : Attribute
    {
        var v = propertyInfo.GetCustomAttribute<T>();
        return v;
    }

    public static TOut? GiveTo<TOut>(this object @in)
    {
        var tin_propertise = @in.GetType().GetProperties();
        var tout_obj = Activator.CreateInstance(typeof(TOut));
        var tout_propertise = typeof(TOut).GetProperties();
        foreach (PropertyInfo? tout_property in tout_propertise)
        {
            var out_description_name = tout_property.GetAttribute<DescriptionAttribute>()?.Description;
            foreach (PropertyInfo? tin_property in tin_propertise)
            {
                var in_description_name = tin_property.GetAttribute<DescriptionAttribute>()?.Description;
                // 这里为啥不写成一句表达式, 这样更加容易理解
                if (out_description_name != null && out_description_name.Equals(tin_property.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    tout_property.SetValue(tout_obj, tin_property.GetValue(@in));
                    break;
                }
                else if (in_description_name != null && in_description_name.Equals(tout_property.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    tout_property.SetValue(tout_obj, tin_property.GetValue(@in));
                    break;
                }
                else if (tout_property.Name.Equals(tin_property.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    tout_property.SetValue(tout_obj, tin_property.GetValue(@in));
                    break;
                }
            }
        }
        TOut? target_obj = (TOut)tout_obj!;
        return target_obj;
    }

    public static TOut? ConvertTo<TOut>(this object @in)
    {
        var tin_propertise = @in.GetType().GetProperties();
        var tout_obj = Activator.CreateInstance(typeof(TOut));
        var tout_propertise = typeof(TOut).GetProperties();
        foreach (PropertyInfo? tout_property in tout_propertise)
        {
            var out_description_name = tout_property.GetAttribute<DescriptionAttribute>()?.Description;
            foreach (PropertyInfo? tin_property in tin_propertise)
            {
                var in_description_name = tin_property.GetAttribute<DescriptionAttribute>()?.Description;
                var old_value = tin_property.GetValue(@in);
                if (old_value is IEnumerable<object> && !((IEnumerable<object>)old_value).Any() ||
                        old_value is null)
                {
                    continue;
                }

                // 这里为啥不写成一句表达式, 这样更加容易理解
                if (out_description_name != null && out_description_name.Equals(tin_property.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    tout_property.SetValue(tout_obj, tin_property.GetValue(@in));
                    break;
                }
                else if (in_description_name != null && in_description_name.Equals(tout_property.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    tout_property.SetValue(tout_obj, tin_property.GetValue(@in));
                    break;
                }
                else if (tout_property.Name.Equals(tin_property.Name, StringComparison.InvariantCultureIgnoreCase))
                {
                    tout_property.SetValue(tout_obj, tin_property.GetValue(@in));
                    break;
                }
            }
        }
        TOut? target_obj = (TOut)tout_obj!;
        return target_obj;
    }

    public static IList<TOut>? ConvertTo<TOut>(this IEnumerable<object> @in)
    {
        var list = new List<TOut>();
        foreach (var obj in @in)
        {
            var out_obj = obj.ConvertTo<TOut>();
            if (out_obj != null)
                list.Add(out_obj);
        }
        return list;
    }
}
